/* $Id:plan.cc $ */
/*
   Copyright (C) 2007 by Jurjen Stellingwerff <jurjen@stwerff.xs4all.nl>
   Part of the Moros Project http://moros.sourceforge.net/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 3.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#define DEBUG_ROUTINE "plan"

#include <sstream>
#include <fstream>
#include "../general/util.h"
#include "../general/log.h"
#include "../general/channel.h"
#include "plan.h"
#include "army.h"
#include "army.h"
#include "person.h"
#include "../general/general.h"

plan::plan() {
    nr=0;
    type=-1;
    planned=0;
    finished=0;
    done=0;
    what=0;
    contributers=map<string,class contributers>();
    persons=map<string,class contractors>();
    priority=0;
    location=0;
}

// Field : nr

const int plan::getNr() const { return nr; }
void plan::setNr(const int v) { nr=v; }
int plan::operator<(const class plan &ck) const { return (this->nr < ck.nr)?1:0; }

// Field : type

const string planType[]={"create","patrol","defend","destroy","pillage","conquer","scout","trade"};
const int plan::getType() const { return type; }
const string plan::showType() const {
    if (type<0) return "";
    else return planType[type];
}
void plan::setType(const int  v) {
    if (v<0 || (unsigned int)v >= sizeof planType/sizeof planType[0]) type=-1;
    else type=v;
}
void plan::setType(const string v) {
    type=-1;
    loopArray(planType, tp, string) {
        if (v==*tp) {type=tp_i; break; }
    }
    if (type==-1) dbg_state("Enumerate plan.type unknown '%s'", v.c_str());
}

// Field : planned

const int plan::getPlanned() const { return planned; }
void plan::setPlanned(const int v) { planned=v; }

// Field : finished

const int plan::getFinished() const { return finished; }
void plan::setFinished(const int v) { finished=v; }

// Field : done

const int plan::getDone() const { return done; }
void plan::setDone(const int v) { done=v; }

// Field : what

class army& plan::getWhat() const { if (what==0) throw nullpointer(); return *what; }
void plan::setWhat(class army &v) { what=&v; }

// Field : contributers

class contributers& plan::getContributers(const string v) { return contributers[v]; }
map<string,class contributers>& plan::listContributers() { return contributers; }
void plan::setContributers(class contributers &v) {
    contributers[v.getArmy().getName()]=v;
}
void plan::delContributers(const string v) { contributers.erase(v); }
const bool plan::isContributers(const string v) const { return contributers.count(v)>0; }

// Field : persons

class contractors& plan::getPersons(const string v) { return persons[v]; }
map<string,class contractors>& plan::listPersons() { return persons; }
void plan::setPersons(class contractors &v) {
    persons[v.getPerson().getName()]=v;
}
void plan::delPersons(const string v) { persons.erase(v); }
const bool plan::isPersons(const string v) const { return persons.count(v)>0; }

// Field : priority

const int plan::getPriority() const { return priority; }
void plan::setPriority(const int v) { priority=v; }

// Field : location

const int plan::getLocation() const { return location; }
void plan::setLocation(const int  v) { location=v; }
const string plan::showLocation() const {
    stringstream res;
    res << "(" << (location & 0xffff) << "," << (location << 16) << ")";
    return res.str();
}

void plan::save(class channel &ch) {
    ch.write("plan", "");
    ch.write("n", getNr());
    ch.write("t", getType());
    ch.write("p", getPlanned());
    ch.write("f", getFinished());
    ch.write("d", getDone());
    ch.write("w", getWhat().getName());
    loopPlanContributers(this, s_contributers) {
        s_contributers->save(ch);
    }
    loopPlanPersons(this, s_persons) {
        s_persons->save(ch);
    }
    ch.write("pr", getPriority());
    ch.write("l", getLocation());
}

void plan::load(class channel &ch) {
    if (ch.key=="n" || ch.key=="nr") { setNr(atoi(ch.value.c_str())); ch.next(); }
    if (ch.key=="t" || ch.key=="type") { setType(ch.value); ch.next(); }
    if (ch.key=="p" || ch.key=="planned") { setPlanned(atoi(ch.value.c_str())); ch.next(); }
    if (ch.key=="f" || ch.key=="finished") { setFinished(atoi(ch.value.c_str())); ch.next(); }
    if (ch.key=="d" || ch.key=="done") { setDone(atoi(ch.value.c_str())); ch.next(); }
    if (ch.key=="w" || ch.key=="what") {
        if (!army_repo.isArmy(ch.value)) {
            dbg_state("link unknown army %s", ch.value.c_str());
            class army rec;
            rec.setName(ch.value);
            army_repo.setArmy(rec);
        }
        setWhat(army_repo.getArmy(ch.value));
        ch.next();
    }
    while (ch.key=="contributers" || ch.key=="contributers") {
        ch.next();
        class contributers rec;
        rec.load(ch);
        setContributers(rec);
    }
    while (ch.key=="contractors" || ch.key=="persons") {
        ch.next();
        class contractors rec;
        rec.load(ch);
        setPersons(rec);
    }
    if (ch.key=="pr" || ch.key=="priority") { setPriority(atoi(ch.value.c_str())); ch.next(); }
    if (ch.key=="l" || ch.key=="location") { setLocation(atoi(ch.value.c_str())); ch.next(); }
}

void plan::xml(ofstream &f, int l, int r) {
    f << ncpy(l, "  ") << "<plan nr=\"" << getNr() <<
    "\" type=\"" << showType() <<
    "\" planned=\"" << getPlanned() <<
    "\" finished=\"" << getFinished() <<
    "\" done=\"" << getDone() <<
    "\" priority=\"" << getPriority() <<
    "\" location_x=\"" << (getLocation() & 0xffff) <<
    "\" location_y=\"" << (getLocation() << 16) <<
    "\">" << endl;
    if (r<2) try {
        getWhat().xml(f,l+1,r+1);
    } catch (nullpointer n) {}
    if (r==0) {
        loopPlanContributers(this, s_contributers) {
            s_contributers->xml(f,l+1);
        }
        loopPlanPersons(this, s_persons) {
            s_persons->xml(f,l+1);
        }
    }
    f << ncpy(l, "  ") << "</plan>" << endl;
}

// Repository

planRepository plan_repo;

planRepository::planRepository() { max_nr=0; }
class plan& planRepository::getPlan(const int v) { return plans[v]; }
void planRepository::setPlan(class plan& v) {
    if (v.getNr()==0) v.setNr(++max_nr);
    plans[v.getNr()]=v;
}
map<int,class plan>& planRepository::listPlan() { return plans; }
void planRepository::delPlan(const int v) { plans.erase(v); }
const bool planRepository::isPlan(const int v) const { return plans.count(v)>0; }
void planRepository::save(class channel &ch) {
    loopPlans(rec) {
        rec->save(ch);
    }
}

bool planRepository::load(class channel &ch) {
    if (ch.key=="plan") {
        ch.next();
        class plan rec;
        rec.load(ch);
        setPlan(rec);
        return true;
    }
    return false;
}
